Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * Voltmeter Clock - 2019
- * A clock using converted analogue 1000v meters and PWM to tell the time
- * Inspired by u/MrMaverick82 (Michael Teeuw) reddit post: https://www.reddit.com/r/DIY/comments/8s1efr/due_to_my_dads_fascination_for_analog_volt_meters/
- * Most of the code here is from above project, with some additions/subtractions
- * Original code and project can be found: https://github.com/MichMich/AnalogVoltMeterClock
- * This project code can be found: https://pastebin.com/gdq0zPUh
- *
- * ADDED: Automatic adjustment for Daylight Savings
- * ADDED: Colour adjustable RGB LEDs for effects (simple here, could be as complex as desired,
- * different colours for AM/PM etc etc)
- *
- * LICENSE: Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"). For more info see LICENSE at bottom of this file.
- */
- #include <DS3232RTC.h> // https://github.com/PaulStoffregen/DS1307RTC
- #include <Timezone.h> // https://github.com/JChristensen/Timezone
- #include <TimeLib.h>
- #include "RTClib.h"
- #include <Arduino.h>
- #include <Wire.h>
- #include <Adafruit_NeoPixel.h>
- #include <Streaming.h>
- // Define the Pins we are using.
- #define PIN_METER_HOUR 3
- #define PIN_METER_MIN 5
- #define PIN_METER_SEC 6
- // Define the minimum and maximum PWM values for all the meters.
- // These values can be used to calibrate the meters.
- #define MINIMUM_PWM_VALUE_HOUR 18
- #define MAXIMUM_PWM_VALUE_HOUR 240
- #define MINIMUM_PWM_VALUE_MIN 1
- #define MAXIMUM_PWM_VALUE_MIN 221
- #define MINIMUM_PWM_VALUE_SEC 5
- #define MAXIMUM_PWM_VALUE_SEC 235
- //Define the neopixel settings
- #define PIN 2
- #define NUMPIXELS 3
- Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
- TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60}; //British Summer Time
- TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0}; //Standard Time
- Timezone UK(BST, GMT);
- // If TimeChangeRules are already stored in EEPROM, comment out the three
- // lines above and uncomment the line below.
- //Timezone myTZ(100); //assumes rules stored at EEPROM address 100
- TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
- time_t utc, local;
- void setup()
- {
- Serial.begin(115200);
- setSyncProvider(RTC.get); // the function to get the time from the RTC
- if(timeStatus()!= timeSet)
- Serial.println("Unable to sync with the RTC");
- else
- Serial.println("RTC has set the system time");
- // Configure all the pin modes for all connected pins.
- pinMode(PIN_METER_HOUR, OUTPUT);
- pinMode(PIN_METER_MIN, OUTPUT);
- pinMode(PIN_METER_SEC, OUTPUT);
- //start the neopixel library
- pixels.begin();
- // Initiate the power-on self test by running the start sequence.
- startSequence();
- }
- void loop(void)
- {
- Serial.println();
- utc = now();
- printTime(utc, "UTC");
- local = UK.toLocal(utc, &tcr);
- printTime(local, tcr -> abbrev);
- delay(1000);
- static time_t tLast;
- time_t t;
- tmElements_t tm;
- //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s
- if (Serial.available() >= 12) {
- //note that the tmElements_t Year member is an offset from 1970,
- //but the RTC wants the last two digits of the calendar year.
- //use the convenience macros from Time.h to do the conversions.
- int y = Serial.parseInt();
- if (y >= 100 && y < 1000)
- Serial << F("Error: Year must be two digits or four digits!") << endl;
- else {
- if (y >= 1000)
- tm.Year = CalendarYrToTm(y);
- else //(y < 100)
- tm.Year = y2kYearToTm(y);
- tm.Month = Serial.parseInt();
- tm.Day = Serial.parseInt();
- tm.Hour = Serial.parseInt();
- tm.Minute = Serial.parseInt();
- tm.Second = Serial.parseInt();
- t = makeTime(tm);
- RTC.set(t); //use the time_t value to ensure correct weekday is set
- setTime(t);
- Serial << F("RTC set to: ");
- printTime(t, local);
- Serial << endl;
- //dump any extraneous input
- while (Serial.available() > 0) Serial.read();
- }
- }
- t = now();
- if (t != tLast) {
- tLast = t;
- if (second(t) == 0) {
- float c = RTC.temperature() / 4.;
- float f = c * 9. / 5. + 32.;
- Serial << F(" ") << c << F(" C ") << f << F(" F");
- }
- // Update the meters by calling the `displayTime()` method.
- displayTime();
- Serial << endl;
- }
- }
- // format and print a time_t value, with a time zone appended.
- void printDateTime(time_t t, const char *tz)
- {
- char buf[32];
- char m[4]; // temporary storage for month string (DateStrings.cpp uses shared buffer)
- strcpy(m, monthShortStr(month(t)));
- sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s",
- hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz);
- Serial.println(buf);
- }
- /**
- * Slowly animate one meter to the maximum value and back.
- * This animation is used in the start sequence. Not only does it look
- * cool. It's also a way to test the meters.
- *
- * @param uint8_t pin The pin of the meter.
- * @param uint8_t min The meter's minimum PWM value.
- * @param uint8_t max The meter's maximum PWM value.
- */
- void animateMeter(uint8_t pin, uint8_t min, uint8_t max) {
- uint8_t v;
- for (v = min; v <= max; v++) {
- analogWrite(pin, v);
- delay(2);
- }
- delay(100);
- for (v = max; v >= min; v--) {
- analogWrite(pin, v);
- delay(2);
- }
- delay(100);
- }
- /**
- * Run the startup sequence by animating all three meters sequentially.
- */
- void startSequence() {
- pixels.setPixelColor(0, pixels.Color(255,51,20));
- pixels.setPixelColor(1, pixels.Color(255,51,20));
- pixels.setPixelColor(2, pixels.Color(255,51,20));
- pixels.show();
- delay(500);
- pixels.setPixelColor(0, pixels.Color(0,0,0));
- pixels.setPixelColor(1, pixels.Color(0,0,0));
- pixels.setPixelColor(2, pixels.Color(0,0,0));
- pixels.show();
- delay(500);
- pixels.setPixelColor(0, pixels.Color(255,51,20));
- pixels.setPixelColor(1, pixels.Color(255,51,20));
- pixels.setPixelColor(2, pixels.Color(255,51,20));
- pixels.show();
- delay(500);
- pixels.setPixelColor(0, pixels.Color(0,0,0));
- pixels.setPixelColor(1, pixels.Color(0,0,0));
- pixels.setPixelColor(2, pixels.Color(0,0,0));
- pixels.show();
- delay(500);
- pixels.setPixelColor(0, pixels.Color(255,51,20));
- pixels.setPixelColor(1, pixels.Color(255,51,20));
- pixels.setPixelColor(2, pixels.Color(255,51,20));
- pixels.show();
- delay(250);
- animateMeter(PIN_METER_HOUR, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR);
- animateMeter(PIN_METER_MIN, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN);
- animateMeter(PIN_METER_SEC, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC);
- }
- /**
- * The method to update the time displayed on the the meter.
- */
- void displayTime() {
- // Since the real time clock returns a 24 hour format,
- // we need to convert the hour value to 12 hour format and store in temporary variable 'h'.
- // For minutes and seconds we can just directly use the
- // properties on the 'time(local)' object. No need to store those
- // in a temporary variable.
- int8_t h = (hour(local) == 0 || hour(local) == 12) ? 12 : hour(local) % 12;
- // Convert the time values to PWM values by using map ...
- // and set that value as the PWM value using analogWrite.
- analogWrite(PIN_METER_HOUR, map(h, 1, 12, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR));
- analogWrite(PIN_METER_MIN, map(minute(local), 0, 60, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN));
- analogWrite(PIN_METER_SEC, map(second(local), 0, 60, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC));
- }
- //Function to print time with time zone
- void printTime(time_t t, char *tz)
- {
- sPrintI00(hour(t));
- sPrintDigits(minute(t));
- sPrintDigits(second(t));
- Serial.print(' ');
- Serial.print(dayShortStr(weekday(t)));
- Serial.print(' ');
- sPrintI00(day(t));
- Serial.print(' ');
- Serial.print(monthShortStr(month(t)));
- Serial.print(' ');
- Serial.print(year(t));
- Serial.print(' ');
- Serial.print(tz);
- Serial.println();
- }
- //Print an integer in "00" format (with leading zero).
- //Input value assumed to be between 0 and 99.
- void sPrintI00(int val)
- {
- if (val < 10) Serial.print('0');
- Serial.print(val, DEC);
- return;
- }
- //Print an integer in ":00" format (with leading zero).
- //Input value assumed to be between 0 and 99.
- void sPrintDigits(int val)
- {
- Serial.print(':');
- if(val < 10) Serial.print('0');
- Serial.print(val, DEC);
- }
- /**
- * ORIGINAL CODE Copyright (c) 2018 Michael Teeuw
- * MODIFIED CODE Copyright (c) 2019 Andrew O'Donnell
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement